<?php
define('XSD_PARSER_ATTR', 1);
define('XSD_PARSER_ELE', 2);
define('XSD_PARSER_MULTI_ELE', 3);

class base_xsdparser {

    var $_depth = array();

    var $_last_entity = array();

    var $_xsd_ns = 'http://www.w3.org/2001/xmlschema';

    static $xsdlib = array();

    function &parse($xsdfile) {
        if (! isset(self::$xsdlib[$xsdfile])) {
            $this->_buff = array(
                'elements' => array(),
                'type' => array()
            );
            $this->_ns_len = strlen($this->_xsd_ns) + 1;
            $this->_parse_xsd_file($xsdfile);
            self::$xsdlib[$xsdfile] = $this->_buff;
        }
        return self::$xsdlib[$xsdfile];
    }

    function _start_element($parser, $name, $attrs) {
        $is_entity = false;
        $last_entity = end($this->_last_entity);
        
        if ($this->_ns_len)
            $name = substr($name, $this->_ns_len);
        
        if ($name == 'ELEMENT') {
            if (isset($attrs['NAME'])) {
                $tagname = $attrs['NAME'];
                $this->_buff['elements'][$attrs['NAME']] = array(
                    '_tag' => $tagname
                );
                $element = $this->_buff['elements'][$attrs['NAME']];
                array_push($this->_last_entity, $attrs['NAME']);
                $is_entity = true;
            } elseif (isset($attrs['REF'])) {
                $tagname = $attrs['REF'];
                $element = $this->_buff['elements'][$attrs['REF']];
            }
            
            if ($last_entity) {
                $this->_buff['elements'][$last_entity][$tagname] = array(
                    (isset($attrs['MAXOCCURS']) && $attrs['MAXOCCURS'] > '1') ? XSD_PARSER_MULTI_ELE : XSD_PARSER_ELE
                );
            }
        } elseif ($name == 'ATTRIBUTE') {
            $this->_buff['elements'][$last_entity]['_attrs']++;
            $this->_buff['elements'][$last_entity][$attrs['NAME']] = array(
                XSD_PARSER_ATTR,
                isset($attrs['USE']) ? $attrs['USE'] : 'optional'
            );
        }
        array_push($this->_depth, $is_entity);
    }

    function _end_element($parser, $name) {
        if (array_pop($this->_depth)) {
            array_pop($this->_last_entity);
        }
    }

    function _parse_xsd_file($xsdfile) {
        $xml_parser = xml_parser_create_ns();
        xml_set_element_handler($xml_parser, array(
            &$this,
            '_start_element'
        ), array(
            &$this,
            '_end_element'
        ));
        
        $p = strpos($xsdfile, '_');
        if (defined('CUSTOM_CORE_DIR') && file_exists(CUSTOM_CORE_DIR . '/' . ($app_id ? $app_id : $this->app->app_id) . '/view/' . $tmpl_file)) {
            $xmldir = CUSTOM_CORE_DIR . '/' . substr($xsdfile, 0, $p) . '/xmlschema/' . substr($xsdfile, $p + 1) . '.xsd';
        } else {
            $xmldir = APP_DIR . '/' . substr($xsdfile, 0, $p) . '/xmlschema/' . substr($xsdfile, $p + 1) . '.xsd';
        }
        if (! ($fp = fopen($xmldir, "r"))) {
            die("could not open XML input:" . $xsdfile);
        }
        
        while ($data = fread($fp, 4096)) {
            if (! xml_parse($xml_parser, $data, feof($fp))) {
                die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($xml_parser)), xml_get_current_line_number($xml_parser)));
            }
        }
        xml_parser_free($xml_parser);
    }
}
